import os
import random
import re
import string
import subprocess
import sys
from datetime import datetime, time


class Color:
    @staticmethod
    def green(msg, is_print=True):
        """
        绿色提示
        :param msg:
        :param is_print: 是否打印，不打印就返回带颜色的文本
        :return:
        """
        msg = '\033[32m {} \033[0m'.format(msg)
        if is_print:
            print(msg)
        else:
            return msg

    @staticmethod
    def yellow(msg, is_print=True):
        """
        黄色提示
        :param msg:
        :param is_print: 是否打印，不打印就返回带颜色的文本
        :return:
        """
        msg = '\033[33m\033[01m {} \033[0m'.format(msg)
        if is_print:
            print(msg)
        else:
            return msg

    @staticmethod
    def red(msg, is_print=True):
        """
        红色提示
        :param msg:
        :param is_print: 是否打印，不打印就返回带颜色的文本
        :return:
        """
        msg = '\033[31m\033[01m {} \033[0m'.format(msg)
        if is_print:
            print(msg)
        else:
            return msg


class Bash:
    @staticmethod
    def get_run_cmd_result(cmd: str, print_cmd: bool = False, ignore_error: bool = False):
        """
        获取命令执行后的返回结果
        :param ignore_error:
        :param cmd:
        :param print_cmd:
        :return:
        """
        if not cmd:
            raise Exception('bash 命令不存在')
        if print_cmd:
            Color.green(cmd)
        cp = subprocess.run(cmd, shell=True, capture_output=True, encoding="utf-8", text=True)
        if cp.returncode != 0:
            if ignore_error:
                if print_cmd:
                    Color.yellow(cp.stderr)
                    Color.yellow(cp.stdout)
                return ''
            if cp.stderr:
                raise Exception(cp.stderr)
            elif cp.stdout:
                raise Exception(cp.stdout)
            else:
                # 返回结果不为 0 且没有报错没有输出只是没匹配到结果而不是命令指令错误
                return ''
        stdout = cp.stdout
        return stdout

    @staticmethod
    def is_cmd_out(cmd: str, print_cmd: bool = False):
        """
        bash 命令是否有输出
        :param cmd:
        :param print_cmd:
        :return:
        """
        result = Bash.get_run_cmd_result(cmd, print_cmd)
        if result:
            return True
        return False

    @staticmethod
    def only_run_cmd(cmd: str, print_cmd: bool = False):
        """
        仅执行命令，实时输出结果
        :param cmd:
        :param print_cmd:
        :return:
        """
        if not cmd:
            raise Exception('bash 命令不存在')
        if print_cmd:
            Color.green(cmd)
        return_code = os.system(cmd)
        if return_code != 0:
            Color.red('命令执行错误: ' + cmd)
            sys.exit(0)


class File:
    @staticmethod
    def file_exits(file_path: str):
        """
        文件是否存在
        :param file_path:
        :return:
        """
        if not file_path:
            raise Exception('文件路径不存在：' + file_path)
        return os.path.exists(file_path)

    @staticmethod
    def check_string_in_file(file_path, target_string):
        """
        判断文件中是否包含某个字符串
        :param file_path:
        :param target_string:
        :return:
        """
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                # 逐行读取文件内容
                for line in file:
                    # 判断目标字符串是否在当前行中
                    if target_string in line:
                        return True
        except FileNotFoundError:
            raise Exception('文件不存在：' + file_path)
        except Exception as e:
            raise Exception(f"发生错误：{e}")
        # 文件中未找到目标字符串
        return False

    @staticmethod
    def list_dir(path: str, list_name=None):
        """
        获取指定路径下的所有文件路径
        :param path:
        :param list_name:
        :return:
        """
        if list_name is None:
            list_name = []
        for file in os.listdir(path):
            file_path = os.path.join(path, file)
            if os.path.isdir(file_path):
                File.list_dir(file_path, list_name)
            else:
                list_name.append(file_path)

    @staticmethod
    def path_files(path: str):
        """
        获取指定路径下的文件路径
        :param path:
        :return:
        """
        files = []
        for file in os.listdir(path):
            file_path = os.path.join(path, file)
            files.append(file_path)
        return files


class Git:
    @staticmethod
    def get_commit(path: str):
        """
        获取当前 git 版本
        :return:
        """
        if path is None:
            Color.red('地址不存在')
            sys.exit(0)
        commit = Bash.get_run_cmd_result('git -C ' + path + " log -1 | grep ^commit | awk -F ' ' '{print $2}'")
        if not commit:
            Color.red('版本不存在: {}'.format(path))
            sys.exit(0)
        return commit

    @staticmethod
    def get_branch(path: str):
        """
        获取当前分支
        :param path:
        :return:
        """
        if path is None:
            Color.red('地址不存在')
            sys.exit(0)
        branch = Bash.get_run_cmd_result(
            'git -C ' + path + " status | grep 'On branch' | awk -F 'On branch' '{print $2}'").strip()
        if not branch:
            Color.red('分支不存在: {}'.format(path))
            sys.exit(0)
        return branch

    @staticmethod
    def is_git(path: str):
        """
        判断路径是否是 git 仓库
        :param path:
        :return:
        """
        if path is None:
            Color.red('地址不存在')
            sys.exit(0)
        if os.path.isfile(path):
            return False
        cp = subprocess.run('git -C {} rev-parse --is-inside-work-tree'.format(path), shell=True, capture_output=True,
                            encoding="utf-8", text=True)
        if cp.stdout.strip() == 'true':
            return True
        return False


class ValidateUtil:
    @staticmethod
    def validate_phone_number(phone_number: str) -> bool:
        """
        校验中国手机号
        :param phone_number:
        :return:
        """
        # 中国手机号的正则表达式，11位数字，以1开头，第二位是3-9之间的数字
        pattern = r"^1[3-9]\d{9}$"
        # 使用 re.match() 校验手机号是否匹配正则表达式
        return re.match(pattern, phone_number) is not None


class StringUtil:
    @staticmethod
    def get_random_string(length: int) -> str:
        return ''.join(random.choices(string.ascii_letters, k=length))


class DateUtil:
    @staticmethod
    def get_analyze_date(date: datetime) -> dict:
        """
        返回数据 (year=2024, week=34, weekday=6)
        :param date:
        :return:
        """
        temp = date.isocalendar()
        cn_week = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
        return dict(year=temp[0], week=temp[1], weekday=temp[2], cn_week=cn_week[temp[2] - 1])

    @staticmethod
    def get_begin_timestamp(datetime_input: datetime) -> datetime:
        """

        :rtype: object
        """
        return datetime.combine(datetime_input, time.min)

    @staticmethod
    def get_end_timestamp(datetime_input: datetime) -> datetime:
        return datetime(datetime_input.year, datetime_input.month, datetime_input.day, 23, 59, 59, 999000)

    @staticmethod
    def parse_timestamp(datetime_str: str, pattern='%Y-%m-%d %H:%M:%S') -> datetime:
        return datetime.strptime(datetime_str, pattern)

    @staticmethod
    def parse_date(datetime_str: str, pattern='%Y-%m-%d') -> datetime.date:
        return datetime.date(datetime.strptime(datetime_str, pattern))
